#define MT_MM     9
#define MT_NN     19
#define MT_WMASK  0xFFFFFFFFU
#define MT_UMASK  0xFFFFFFFEU
#define MT_LMASK  0x00000001U
#define MT_SHIFT0 12
#define MT_SHIFTB 7
#define MT_SHIFTC 15
#define MT_SHIFT1 18

#include <CL/cl.h>
#include <stdio.h>
#include <stdlib.h>
#include <wtypes.h>
#include <Strsafe.h>
#include <string.h>
#include <string>
#include <vector>
#include <omp.h>
#include <cstdlib>
#include <fstream>
#include <time.h>	
#include <math.h>
#include <conio.h>
#include <iostream>
using namespace std;

typedef struct {
	unsigned int matrix_a;
	unsigned int mask_b;
	unsigned int mask_c;
	unsigned int seed;
} MersenneTwisterConfig;

class MersenneTwister
{
public:
	MersenneTwister(cl_uint count);
	~MersenneTwister();
	// print result 
	void printResult();

	cl_float * getArray() {return randomValue;}

private:
	cl_float				* randomValue;	// output values
	cl_uint					width;			// count values
	MersenneTwisterConfig	* mtConfigs;
	// the memory buffer that is used as input/output for OpenCL kernel 
	cl_mem					outputBuffer;
	cl_mem					mtConfigsBuffer;
	cl_context				context;
	cl_device_id			* devices;
	cl_command_queue		commandQueue;
	cl_program				program;
	// this program uses only one kernel and this serves as a handle to it 
	cl_kernel				kernel;

	// Initialize CL 
	void initializeCL(void);
	// Initialize Host application 
	void initializeHost(void);

	// read to file
	string convertToString(const char * filename);

	// run kernels cl 
	void runCLKernels(void);

	// releases OpenCL resources
	void cleanupCL(void);

	// releases program's resources 
	void cleanupHost(void);

	// Print error
	void printError(cl_int status, char * nameFunction);

};